// Copyright 2022 a.o.smith ALL Rights Reserved
package com.liuxinlong.modules.chimi.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.liuxinlong.common.AosException;
import com.liuxinlong.common.SnowFlake;
import com.liuxinlong.constant.TimeFormatConstants;
import com.liuxinlong.enums.BarPointBusinessEnum;
import com.liuxinlong.enums.ReturnCodes;
import com.liuxinlong.modules.chimi.dto.BarPointsDto;
import com.liuxinlong.modules.chimi.service.BarPointsService;
import com.liuxinlong.modules.dao.BarPointsDao;
import com.liuxinlong.modules.dao.BarPointsFlowDao;
import com.liuxinlong.modules.dao.BarPointsRuleDao;
import com.liuxinlong.modules.dao.BarPointsRuleDetailDao;
import com.liuxinlong.modules.dao.FileManageDao;
import com.liuxinlong.modules.entity.BarPoints;
import com.liuxinlong.modules.entity.BarPointsFlow;
import com.liuxinlong.modules.entity.BarPointsRule;
import com.liuxinlong.modules.entity.BarPointsRuleDetail;
import com.liuxinlong.modules.system.service.UserService;
import com.liuxinlong.utils.IPUtils;
import com.liuxinlong.utils.ObjectUtils;
import com.liuxinlong.utils.RedisUtils;
import com.liuxinlong.utils.TimeUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 论坛积分服务层接口实现
 *
 * @author liuxinlong@hotwater.com.cn
 * @version 1.0.0
 * @since 2023-08-23
 */
@Service
@Slf4j
public class BarPointsServiceImpl implements BarPointsService {

    @Autowired
    private BarPointsDao barPointsDao;

    @Autowired
    private BarPointsRuleDao barPointsRuleDao;

    @Autowired
    private BarPointsRuleDetailDao barPointsRuleDetailDao;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private BarPointsFlowDao barPointsFlowDao;

    @Autowired
    private UserService userService;

    @Autowired
    private FileManageDao fileManageDao;


    @Override
    public Map<String, Object> updateUserPoints(String userId, int business, int luckPoint) {
        int point = business == BarPointBusinessEnum.LUCK_GIFT.getValue() ? luckPoint : BarPointBusinessEnum.getDefaultPointByValue(business);
        if (business != BarPointBusinessEnum.LUCK_GIFT.getValue()) {
            BarPointsRuleDetail detail = getCurrentEffectiveRule(business);
            if (!ObjectUtils.isEmpty(detail)) {
                point = detail.getPoints();
            }
        }
        String currentTime = TimeUtils.getDate(TimeFormatConstants.YYYY_MM_DD_HH_MM_SS);
        if (business == BarPointBusinessEnum.SIGN_IN.getValue()) {
            BarPointsFlow signRecord = barPointsFlowDao.getSignFlow(userId, currentTime.substring(0, 10));
            if (!ObjectUtils.isEmpty(signRecord)) {
                throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "用户已签到，不能再次签到!");
            }
        }

        BarPointsFlow signFlow = new BarPointsFlow();
        signFlow.setId(SnowFlake.nextIdStr());
        signFlow.setUserId(userId);
        signFlow.setPoints(point);
        signFlow.setOperateTime(currentTime);
        signFlow.setType(1);
        signFlow.setSourceType(business);
        barPointsFlowDao.insert(signFlow);
        BarPoints defaultPoints = barPointsDao.selectById(userId);
        Map<String, Object> resultMap = new HashMap<>();
        int userPoint = point;
        if (!ObjectUtils.isEmpty(defaultPoints)) {
            barPointsDao.updatePoint(userId, 1, point);
            resultMap.put("thisPoint", point);
            userPoint = defaultPoints.getPoints() + userPoint;
            resultMap.put("researchPoint", userPoint);
            updateRanking(defaultPoints.getPoints());
        } else {
            BarPoints createPoints = new BarPoints();
            createPoints.setId(userId);
            createPoints.setPoints(point);
            createPoints.setStockPoints(point);
            barPointsDao.insert(createPoints);
            updateRanking(point);
            resultMap.put("thisPoint", point);
            resultMap.put("researchPoint", point);
        }
        Map<String,Map<String,String>> rankMap = barPointsDao.getRankMap();
        int rank = rankMap.containsKey(userId) ? Integer.valueOf(rankMap.get(userId).get("ranks")) : 0;
        resultMap.put("rank",rank);
        Map<String, Object> cache = new HashMap<>();
        cache.put("id", userId);
        cache.put("point", userPoint);
        cache.put("rank",rank);
        redisUtils.setUserPointCache(userId, cache);
        return resultMap;
    }

    /**
     * 查询当前生效规则
     *
     * @param business 业务类型
     * @return 当前生效规则
     */
    private BarPointsRuleDetail getCurrentEffectiveRule(int business) {
        Map<Object, Object> ruleMap = redisUtils.getPointsRulesCache();
        BarPointsRuleDetail detailInfo = null;
        if (ObjectUtils.isEmpty(ruleMap)) {
            String currentTime = TimeUtils.getDate(TimeFormatConstants.YYYY_MM_DD_HH_MM_SS);
            BarPointsRule rule = barPointsRuleDao.getCurrentEffectiveRule(currentTime);
            if (ObjectUtils.isEmpty(rule)) {
                return null;
            }
            Map<String, Object> queryParam = new HashMap<>();
            queryParam.put("ruleId", rule.getId());
            queryParam.put("startNum", 0);
            queryParam.put("pageSize", 100);
            List<BarPointsRuleDetail> detailList = barPointsRuleDetailDao.pageBarPointsRuleDetail(queryParam);
            Map<String, Object> ruleDataMap = new HashMap<>();
            for (BarPointsRuleDetail detail : detailList) {
                ruleDataMap.put(String.valueOf(detail.getSourceType()), detail);
                if (detail.getSourceType() == business) {
                    detailInfo = detail;
                }
            }
            redisUtils.setPointsRulesCache(ruleDataMap);
            return detailInfo;
        }
        if (ruleMap.containsKey(String.valueOf(business))) {
            if (ruleMap.get(String.valueOf(business)) instanceof String) {
                return JSON.parseObject((String) ruleMap.get(String.valueOf(business)), BarPointsRuleDetail.class);
            }
        }
        return null;
    }

    /**
     * 获取排行榜数据
     *
     * @return 排行榜数据
     */
    private Map<String, Object> getRankingCache() {
        Map<Object, Object> forumCacheMap = redisUtils.getForumCache();
        Map<String, Object> cacheMap = new HashMap<>();
        if (ObjectUtils.isEmpty(forumCacheMap)) {
            List<Map<String, Object>> researchPointList = generateAllRanking();
            cacheMap.put("researchPointList", JSON.toJSON(researchPointList).toString());
            List<Map<String, Object>> currentMonthList = generateMonthRanking();
            cacheMap.put("currentMonthList", JSON.toJSON(currentMonthList).toString());
            List<Map<String, Object>> currentDayList = generateWeekRanking();
            cacheMap.put("currentDayList", JSON.toJSON(currentDayList).toString());
            redisUtils.setForumCache(cacheMap);
        } else {
            if (!forumCacheMap.containsKey("researchPointList")) {
                List<Map<String, Object>> researchPointList = generateAllRanking();
                cacheMap.put("researchPointList", JSON.toJSON(researchPointList).toString());
            } else {
                cacheMap.put("researchPointList", forumCacheMap.get("researchPointList"));
            }
            if (!forumCacheMap.containsKey("currentMonthList")) {
                List<Map<String, Object>> currentMonthList = generateMonthRanking();
                cacheMap.put("currentMonthList", JSON.toJSON(currentMonthList).toString());
            } else {
                cacheMap.put("currentMonthList", forumCacheMap.get("currentMonthList"));
            }
            if (!forumCacheMap.containsKey("currentDayList")) {
                List<Map<String, Object>> currentDayList = generateWeekRanking();
                cacheMap.put("currentDayList", JSON.toJSON(currentDayList).toString());
            } else {
                cacheMap.put("currentDayList", forumCacheMap.get("currentDayList"));
            }
            redisUtils.setForumCache(cacheMap);
        }
        return cacheMap;
    }

    /**
     * 计算研值总榜
     *
     * @return 研值总榜
     */
    private List<Map<String, Object>> generateAllRanking() {
        List<BarPointsDto> pointList = barPointsDao.queryTopTen();

        // 积分榜
        Set<String> fileSet = pointList.stream().map(BarPointsDto::getUserPic).collect(Collectors.toSet());
        String fileIds = StringUtils.strip(fileSet.toString().replaceAll(" ", "").replaceAll(",null", "").replaceAll(",,", ","), "[]");

        Set<String> fileIdList = new HashSet<>(Arrays.asList(fileIds.trim().split(",")));
        Map<String, Map<String, Object>> fileMap = new HashMap<>();
        if (!ObjectUtils.isEmpty(fileIdList)) {
            fileMap = fileManageDao.getFileMapByIds(fileIdList);
        }
        String currentIp = IPUtils.getCurrentIp();
        List<Map<String, Object>> researchPointList = new ArrayList<>();
        int sort = 1;
        if (!ObjectUtils.isEmpty(pointList)) {
            for (BarPointsDto points : pointList) {
                Map<String, Object> item = ObjectUtils.object2Map(points);
                item.put("sort", sort);
                item.put("userId", points.getId());
                item.put("userPic", fileMap.containsKey(points.getUserPic()) ?
                        String.valueOf(fileMap.get(points.getUserPic()).get("path")).replace("upload", "http:\\\\" + currentIp + ":8090\\preview\\upload")
                        : "");
                researchPointList.add(item);
                sort++;
            }
        }
        return researchPointList;
    }

    /**
     * 计算研值月榜
     *
     * @return 研值月榜
     */
    private List<Map<String, Object>> generateMonthRanking() {
        List<Map<String, Object>> currentMonthList = new ArrayList<>();
        List<Map<String, Object>> monthRankList = barPointsFlowDao.getTopTen(TimeUtils.getMonthFirstDay());
        int sort = 1;
        if (!ObjectUtils.isEmpty(monthRankList)) {
            for (Map<String, Object> pointMap : monthRankList) {
                Map<String, Object> item = new HashMap<>();
                item.put("sort", sort);
                item.put("points", pointMap.get("totalPoints"));
                String userId = (String) pointMap.get("userId");
                item.put("id", userId);
                item.put("userId", userId);
                Map<String, Object> userInfo = userService.queryUserBase(userId);
                item.put("userName", userInfo.get("name"));
//                item.put("sn", userInfo.get("fileUrl"));
                item.put("userPic", userInfo.get("fileUrl"));
                currentMonthList.add(item);
                sort++;
            }
        }
        return currentMonthList;
    }

    /**
     * 计算研值周榜
     *
     * @return 研值周榜
     */
    private List<Map<String, Object>> generateWeekRanking() {
        List<Map<String, Object>> currentWeekList = new ArrayList<>();
        List<Map<String, Object>> weekRankList = barPointsFlowDao.getTopTen(TimeUtils.getWeekStart());
        int sort = 1;
        if (!ObjectUtils.isEmpty(weekRankList)) {
            for (Map<String, Object> pointMap : weekRankList) {
                Map<String, Object> item = new HashMap<>();
                item.put("sort", sort);
                item.put("points", pointMap.get("totalPoints"));
                String userId = (String) pointMap.get("userId");
                item.put("id", userId);
                item.put("userId", userId);
                Map<String, Object> userInfo = userService.queryUserBase(userId);
                item.put("userName", userInfo.get("name"));
//                item.put("sn", userInfo.get("fileUrl"));
                item.put("userPic", userInfo.get("fileUrl"));
                currentWeekList.add(item);
                sort++;
            }
        }
        return currentWeekList;
    }

    private List<Map<String, Object>> updatePointRanking() {
        List<Map<String, Object>> pointRankingList = new ArrayList<>();
        return pointRankingList;
    }

    private List<Map<String, Object>> updateDayRanking() {
        List<Map<String, Object>> dayRankingList = new ArrayList<>();
        return dayRankingList;
    }

    private List<Map<String, Object>> updateMonthRanking() {
        List<Map<String, Object>> monthRankingList = new ArrayList<>();
        return monthRankingList;
    }


    private void updateRanking(int userPoints) {
        Map<String, Object> cacheMap = getRankingCache();
        List<Map<String, Object>> researchPointList = (List<Map<String, Object>>) JSONArray.parseObject((String) cacheMap.get("researchPointList"), List.class);
        if (researchPointList.size() < 10) {
            List<Map<String, Object>> newResearchPointList = generateAllRanking();
            cacheMap.put("researchPointList", JSON.toJSON(newResearchPointList).toString());
        } else {
            for (Map<String, Object> point : researchPointList) {
                if (((Integer) point.get("points")).intValue() < userPoints) {
                    List<Map<String, Object>> newResearchPointList = generateAllRanking();
                    cacheMap.put("researchPointList", JSON.toJSON(newResearchPointList).toString());
                    break;
                }
            }
        }
        List<Map<String, Object>> currentDayList = (List<Map<String, Object>>) JSONArray.parseObject((String) cacheMap.get("currentDayList"), List.class);
        if (currentDayList.size() < 10) {
            List<Map<String, Object>> newCurrentDayList = generateWeekRanking();
            cacheMap.put("currentDayList", JSON.toJSON(newCurrentDayList).toString());
        } else {
            for (Map<String, Object> point : currentDayList) {
                if (((Integer) point.get("points")).intValue() < userPoints) {
                    List<Map<String, Object>> newCurrentDayList = generateWeekRanking();
                    cacheMap.put("currentDayList", JSON.toJSON(newCurrentDayList).toString());
                    break;
                }
            }
        }
        List<Map<String, Object>> currentMonthList = (List<Map<String, Object>>) JSONArray.parseObject((String) cacheMap.get("currentMonthList"), List.class);
        if (currentMonthList.size() < 10) {
            List<Map<String, Object>> newCurrentMonthList = generateMonthRanking();
            cacheMap.put("currentMonthList", JSON.toJSON(newCurrentMonthList).toString());
        } else {
            for (Map<String, Object> point : currentMonthList) {
                if (((Integer) point.get("points")).intValue() < userPoints) {
                    List<Map<String, Object>> newCurrentMonthList = generateMonthRanking();
                    cacheMap.put("currentMonthList", JSON.toJSON(newCurrentMonthList).toString());
                    break;
                }
            }
        }
        redisUtils.setForumCache(cacheMap);
    }
}
